// Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use bytes::{Buf, BufMut, TryGetError};

use crate::{deploy::MergeMode, Arch};

pub trait BufExt: Buf {
    fn try_get_bool(&mut self) -> Result<bool, TryGetError> {
        Ok(self.try_get_u8()? != 0)
    }
    
    fn try_get_string(&mut self) -> Result<String, TryGetError> {
        let len = self.try_get_u32_le()?;
        let mut bytes = vec![0u8; len as usize];
        self.try_copy_to_slice(&mut bytes)?;
        Ok(unsafe { String::from_utf8_unchecked(bytes) })
    }

    fn try_get_strings_with_len(&mut self) -> Result<Vec<String>, TryGetError> {
        let len = self.try_get_u32_le()?;
        let mut result = Vec::with_capacity(len as usize);
        for _ in 0..len {
            result.push(self.try_get_string()?);
        }
        Ok(result)
    }
}

pub trait BufMutExt: BufMut {
    fn put_bool(&mut self, b: bool) {
        self.put_u8(b as u8);
    }

    fn put_str(&mut self, s: &str) {
        self.put_u32_le(s.len() as u32);
        self.put_slice(s.as_bytes());
    }

    fn put_strs<'a, I>(&mut self, iter: I)
    where I: IntoIterator<Item = &'a str>
    {
        for s in iter {
            self.put_str(s);
        }
    }

    fn put_strs_with_len<'a, I>(&mut self, iter: I, len: u32)
    where I: IntoIterator<Item = &'a str>
    {
        self.put_u32_le(len);
        self.put_strs(iter);
    }

    fn put_merge_mode(&mut self, mode: MergeMode) {
        self.put_u8(mode as u8);
    }

    fn put_arch(&mut self, arch: Arch) {
        self.put_u8(arch as u8);
    }
}

impl<T: Buf> BufExt for T {}
impl<T: BufMut> BufMutExt for T {}
